package com.jyy.prefabricated.controller;

import com.jyy.prefabricated.common.AjaxResult;
import com.jyy.prefabricated.dto.LoginDto;
import com.jyy.prefabricated.entity.SysUser;
import com.jyy.prefabricated.enums.UserTypeEnum;
import com.jyy.prefabricated.exception.CustomException;
import com.jyy.prefabricated.jwt.JwtTokenUtil;
import com.jyy.prefabricated.security.CustomUserDetailsService;
import com.jyy.prefabricated.service.StudentExamService;
import com.jyy.prefabricated.service.SysUserService;
import com.jyy.prefabricated.utils.UserSessionUtil;
import com.jyy.prefabricated.vo.StudentExamVo;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @version 1.0.0
 * @author: zjj
 */
@Slf4j
@RequestMapping("/api")
@RestController
public class LoginController {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private StudentExamService studentExamService;

    @Autowired
    protected WxMpService wxMpService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private CustomUserDetailsService customUserDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 移动端登录
     * @param dto
     * @param request
     * @return
     */
    @PostMapping("/mobile/login")
    public AjaxResult mobileLogin(@RequestBody LoginDto dto, HttpServletRequest request){
        SysUser user = sysUserService.selectByUsernameOrIdCard(dto.getUsername());
        if(user != null &&  UserTypeEnum.ADMIN.getValue().equals(user.getUserType())){
            throw new CustomException("当前用户无权限登录");
        }
//        if(user != null && StringUtils.isNotBlank(user.getOpenid())){
//            throw new CustomException("请使用微信授权登录");
//        }
        UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken(dto.getUsername(), dto.getPassword());
        String password = authentication.getCredentials().toString();
        Boolean checkPwd = passwordEncoder.matches(password,user.getPassword());
        if(!checkPwd){
            throw new CustomException("用户名或密码错误");
        }
        UserDetails userDetails = customUserDetailsService.loadUserByUsername(dto.getUsername());
        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        // 将 authentication 存入 ThreadLocal，方便后续获取用户信息
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String token = jwtTokenUtil.generateToken(userDetails);
        Map<String,Object> result = new HashMap<>();
        result.put("token",token);
        return AjaxResult.success(result);
    }

    /**
     * 考试系统登录
     * @param dto
     * @param request
     * @return
     */
    @PostMapping("/exam/login")
    public AjaxResult examLogin(@RequestBody LoginDto dto, HttpServletRequest request){
        SysUser user = sysUserService.selectByUsernameOrIdCard(dto.getUsername());
        if(user != null && !UserTypeEnum.STUDENT.getValue().equals(user.getUserType())){
            throw new CustomException("当前用户无权限登录");
        }
        UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken(dto.getUsername(), dto.getPassword());
        String password = authentication.getCredentials().toString();
        Boolean checkPwd = passwordEncoder.matches(password,user.getPassword());
        if(!checkPwd){
            throw new CustomException("用户名或密码错误");
        }
        List<StudentExamVo> list = studentExamService.selectCurrentExamByStudentId(user.getStudent().getId());
        if(list.size() == 0 ){
            throw new CustomException("当前学员无待参加考试");
        }
        UserDetails userDetails = customUserDetailsService.loadUserByUsername(dto.getUsername());
        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        // 将 authentication 存入 ThreadLocal，方便后续获取用户信息
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String token = jwtTokenUtil.generateToken(userDetails);
        Map<String,Object> result = new HashMap<>();
        result.put("token",token);
        return AjaxResult.success(result);
    }

    /**
     * 公众号登录
     * @param code
     * @return
     */
    @GetMapping("/wxmp/login")
    public AjaxResult wxmpLogin(@RequestParam String code ){
        Map<String,Object> result = new HashMap<>();
        WxOAuth2AccessToken accessToken;
        String tk = UserSessionUtil.resolveToken();
        if(StringUtils.isNotBlank(tk)){
            log.info("携带了token来获取openid,token:{}",tk);
            //当前携带了token
            String username = jwtTokenUtil.getUsernameFromToken(tk);
            SysUser user = sysUserService.selectByUsernameOrIdCard(username);
            if(user != null){
                //当前已经是登录状态了
                if(StringUtils.isNotBlank(user.getOpenid())){
                    //当前用户绑定了openid不作操作
                    log.info("当前登录用户已绑定openid，不做操作");
                } else {
                    //没绑定，去做绑定操作
                    try {
                        accessToken = wxMpService.getOAuth2Service().getAccessToken(code);
                        String openid = accessToken.getOpenId();
                        log.info("根据code获取到openid:{},并且执行绑定操作",openid);
                        user.setOpenid(openid);
                        sysUserService.update(user);
                    } catch (WxErrorException e) {
                        log.error(e.getError().toString());
                    }
                }
                //只要是登录状态，返回token
                String newTk = jwtTokenUtil.refreshToken(tk);
                result.put("token",newTk);
                return AjaxResult.success(result);
            }
        }
        //当前用户没有登录的或者token失效，去拿openid
        log.info("当前用户没有登录的或者token失效，去拿openid");
        try {
            accessToken = wxMpService.getOAuth2Service().getAccessToken(code);
            String openid = accessToken.getOpenId();
            SysUser user = sysUserService.selectByOpenid(openid);
            log.info("根据code获取到openid:{}",openid);
            if(user == null ){
                log.info("当前用户没有绑定openid,直接返回openid:{}",openid);
                result.put("openid",openid);
                return AjaxResult.success(result);
            } else {
                UserDetails userDetails = customUserDetailsService.loadUserByUsername(user.getUsername());
                String token = jwtTokenUtil.generateToken(userDetails);
                log.info("当前用户绑定了openid，直接返回token:{}",token);
                result.put("token",token);
                return AjaxResult.success(result);
            }

        } catch (WxErrorException e) {
            log.error(e.getError().toString());
        }
        return AjaxResult.error("获取微信openid异常");
    }
}
